#include "stdlib.h"
#include "stdio.h"
#include <windows.h>
#include <conio.h>
#include <errno.h>
#include <WinDef.h>
#include <winhttp.h>

#include "../../include/msp_cmn.h"
#include "../../include/qivw.h"
#include "../../include/msp_errors.h"

#pragma comment(lib, "winmm.lib")  

 #ifdef _WIN64
 #pragma comment(lib,"../../libs/msc_x64.lib")
 #else
 #pragma comment(lib, "../../libs/msc.lib")
 #endif

#pragma comment(lib, "winhttp.lib")

//ȡļ
#define IVW_AUDIO_FILE_NAME "audio/awake.pcm"
#define FRAME_LEN	640 //16kʵ16bitƵһ֡ĴСΪ640B, ʱ20ms

int wakeupFlage = 0;
void sleep_ms(int ms)
{
	Sleep(ms);
}

void notifyWakeupToServer(const char* wakeupInfo) {
    HINTERNET hSession = NULL, 
             hConnect = NULL,
             hRequest = NULL;
    
    // 初始化WinHTTP
    hSession = WinHttpOpen(L"Wake Notifier",  
                          WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
                          WINHTTP_NO_PROXY_NAME, 
                          WINHTTP_NO_PROXY_BYPASS,
                          0);

    if (hSession) {
        hConnect = WinHttpConnect(hSession, 
                                L"localhost",  // 服务器地址
                                8080,         // 端口
                                0);
    }

    if (hConnect) {
        hRequest = WinHttpOpenRequest(hConnect, 
                                    L"POST",
                                    L"/wakeup", // 新增的唤醒通知端点
                                    NULL, 
                                    WINHTTP_NO_REFERER, 
                                    WINHTTP_DEFAULT_ACCEPT_TYPES,
                                    0);
    }

    if (hRequest) {
        // 发送请求
        BOOL bResults = WinHttpSendRequest(hRequest,
                                         WINHTTP_NO_ADDITIONAL_HEADERS,
                                         0,
                                         (LPVOID)wakeupInfo,
                                         strlen(wakeupInfo),
                                         strlen(wakeupInfo),
                                         0);

        if (bResults) {
            bResults = WinHttpReceiveResponse(hRequest, NULL);
        }
    }

    // 清理资源
    if (hRequest) WinHttpCloseHandle(hRequest);
    if (hConnect) WinHttpCloseHandle(hConnect);
    if (hSession) WinHttpCloseHandle(hSession);
}

int cb_ivw_msg_proc( const char *sessionID, int msg, int param1, int param2, const void *info, void *userData )
{
	if (MSP_IVW_MSG_ERROR == msg) //ѳϢ
	{
		printf("\n\nMSP_IVW_MSG_ERROR errCode = %d\n\n", param1);
	}
	else if (MSP_IVW_MSG_WAKEUP == msg) //ѳɹϢ
	{
		printf("\n\nMSP_IVW_MSG_WAKEUP result = %s\n\n", info);
		wakeupFlage = 1;
		
		// 发送唤醒通知到服务器
		notifyWakeupToServer((const char*)info);
	}
	return 0;
}
//ͨȡƵļѵdemo
void run_ivw(const char *grammar_list, const char* audio_filename ,  const char* session_begin_params)
{
	const char *session_id = NULL;
	int err_code = MSP_SUCCESS;
	FILE *f_aud = NULL;
	long audio_size = 0;
	long real_read = 0;
	long audio_count = 0;
	int count = 0;
	int audio_stat = MSP_AUDIO_SAMPLE_CONTINUE;
	char *audio_buffer=NULL;
	char sse_hints[128];
	if (NULL == audio_filename)
	{
		printf("params error\n");
		return;
	}

	f_aud=fopen(audio_filename, "rb");
	if (NULL == f_aud)
	{
		printf("audio file open failed! \n\n");
		return;
	}
	fseek(f_aud, 0, SEEK_END);
	audio_size = ftell(f_aud);
	fseek(f_aud, 0, SEEK_SET);
	audio_buffer = (char *)malloc(audio_size);
	if (NULL == audio_buffer)
	{
		printf("malloc failed! \n");
		goto exit;
	}
	real_read = fread((void *)audio_buffer, 1, audio_size, f_aud);
	if (real_read != audio_size)
	{
		printf("read audio file failed!\n");
		goto exit;
	}

	session_id=QIVWSessionBegin(grammar_list, session_begin_params, &err_code);
	if (err_code != MSP_SUCCESS)
	{
		printf("QIVWSessionBegin failed! error code:%d\n",err_code);
		goto exit;
	}

	err_code = QIVWRegisterNotify(session_id, cb_ivw_msg_proc,NULL);
	if (err_code != MSP_SUCCESS)
	{
		_snprintf(sse_hints, sizeof(sse_hints), "QIVWRegisterNotify errorCode=%d", err_code);
		printf("QIVWRegisterNotify failed! error code:%d\n",err_code);
		goto exit;
	}
	while(1)
	{
		long len = 10*FRAME_LEN; //16kƵ10֡ ʱ200ms
		audio_stat = MSP_AUDIO_SAMPLE_CONTINUE;
		if(audio_size <= len)
		{
			len = audio_size;
			audio_stat = MSP_AUDIO_SAMPLE_LAST; //һ
		}
		if (0 == audio_count)
		{
			audio_stat = MSP_AUDIO_SAMPLE_FIRST;
		}

		printf("csid=%s,count=%d,aus=%d\n",session_id, count++, audio_stat);
		err_code = QIVWAudioWrite(session_id, (const void *)&audio_buffer[audio_count], len, audio_stat);
		if (MSP_SUCCESS != err_code)
		{
			printf("QIVWAudioWrite failed! error code:%d\n",err_code);
			_snprintf(sse_hints, sizeof(sse_hints), "QIVWAudioWrite errorCode=%d", err_code);
			goto exit;
		}
		if (MSP_AUDIO_SAMPLE_LAST == audio_stat)
		{
			break;
		}
		audio_count += len;
		audio_size -= len;

		sleep_ms(200); //ģ˵ʱ϶10֡ƵʱΪ200ms
	}
	_snprintf(sse_hints, sizeof(sse_hints), "success");

exit:
	if (NULL != session_id)
	{
		QIVWSessionEnd(session_id, sse_hints);
	}
	if (NULL != f_aud)
	{
		fclose(f_aud);
	}
	if (NULL != audio_buffer)
	{
		free(audio_buffer);
	}
}


//˷¼demo
void ivw_demo_microphone(const char *grammar_list, const char* session_begin_params)
{
	const char *session_id = NULL;
	int err_code = MSP_SUCCESS;
	long audio_size = 0;
	long audio_count = 0;
	int count = 0;
	int audio_stat = MSP_AUDIO_SAMPLE_CONTINUE;
	char sse_hints[128];
	DWORD bufsize;
	long len =0;

	HWAVEIN hWaveIn;  //豸
	WAVEFORMATEX waveform; //ɼƵĸʽṹ
	BYTE *pBuffer;//ɼƵʱݻ
	WAVEHDR wHdr; //ɼƵʱݻĽṹ
	HANDLE          wait;

	waveform.wFormatTag = WAVE_FORMAT_PCM;//ʽΪPCM
	waveform.nSamplesPerSec = 16000;//Ƶ
	waveform.wBitsPerSample = 16;//
	waveform.nChannels = 1;//
	waveform.nAvgBytesPerSec = 16000;//ÿ
	waveform.nBlockAlign = 2;//һĴСbitֽ
	waveform.cbSize = 0;//һΪ0

	wait = CreateEvent(NULL, 0, 0, NULL);
	//ʹwaveInOpenƵɼ
	waveInOpen(&hWaveIn, WAVE_MAPPER, &waveform, (DWORD_PTR)wait, 0L, CALLBACK_EVENT);

	bufsize= 1024 * 500;//ʵСڴ洢ƵݣʵڴС¼ʱ䣬ȡڴ

	session_id = QIVWSessionBegin(grammar_list, session_begin_params, &err_code);
	if (err_code != MSP_SUCCESS)
	{
		printf("QIVWSessionBegin failed! error code:%d\n", err_code);
		goto exit;
	}

	err_code = QIVWRegisterNotify(session_id, cb_ivw_msg_proc, NULL);
	if (err_code != MSP_SUCCESS)
	{
		_snprintf(sse_hints, sizeof(sse_hints), "QIVWRegisterNotify errorCode=%d", err_code);
		printf("QIVWRegisterNotify failed! error code:%d\n", err_code);
		goto exit;
	}

	pBuffer = malloc(bufsize);
	wHdr.lpData = (LPSTR)pBuffer;
	wHdr.dwBufferLength = bufsize;
	wHdr.dwBytesRecorded = 0;
	wHdr.dwUser = 0;
	wHdr.dwFlags = 0;
	wHdr.dwLoops = 1;
	waveInPrepareHeader(hWaveIn, &wHdr, sizeof(WAVEHDR));//׼һݿͷ¼
	waveInAddBuffer(hWaveIn, &wHdr, sizeof(WAVEHDR));//ָݿΪ¼뻺
	waveInStart(hWaveIn);//ʼ¼

	//while (audio_count< bufsize && wakeupFlage!=1)//λ
	while (audio_count< bufsize)//
	{
		Sleep(200);//ȴ¼5s

		len = 10 * FRAME_LEN; //16kƵ10֡ ʱ200ms
		audio_stat = MSP_AUDIO_SAMPLE_CONTINUE;
		if (audio_count >= wHdr.dwBytesRecorded)
		{
			len = audio_size;
			audio_stat = MSP_AUDIO_SAMPLE_LAST; //һ
		}
		if (0 == audio_count)
		{
			audio_stat = MSP_AUDIO_SAMPLE_FIRST;
		}

		printf("csid=%s,count=%d,aus=%d\n", session_id, count++, audio_stat);
		err_code = QIVWAudioWrite(session_id, (const void *)&pBuffer[audio_count], len, audio_stat);
		if (MSP_SUCCESS != err_code)
		{
			printf("QIVWAudioWrite failed! error code:%d\n", err_code);
			_snprintf(sse_hints, sizeof(sse_hints), "QIVWAudioWrite errorCode=%d", err_code);
			goto exit;
		}
		if (MSP_AUDIO_SAMPLE_LAST == audio_stat)
		{
			break;
		}
		audio_count += len;
	}
	waveInReset(hWaveIn);//ֹͣ¼
	if (NULL != pBuffer) 
	{
		free(pBuffer);
	}
	_snprintf(sse_hints, sizeof(sse_hints), "success");

exit:
	if (NULL != session_id)
	{
		QIVWSessionEnd(session_id, sse_hints);
	}

}

int main(int argc, char* argv[])
{
	int         ret       = MSP_SUCCESS;
	const char *lgi_param = "appid = 5efaadde, work_dir = .";
	const char *ssb_param = "ivw_threshold=0:1450,sst=wakeup,ivw_res_path =fo|res/ivw/wakeupresource.jet";
	int aud_src = 0;
	/* û¼ */
	ret = MSPLogin(NULL, NULL, lgi_param); //һûڶ룬ǵûhttp://www.xfyun.cnעȡ
	if (MSP_SUCCESS != ret)
	{
		printf("MSPLogin failed, error code: %d.\n", ret);
		goto exit ;//¼ʧܣ˳¼
	}
	printf("\n###############################################################################################################\n");
	printf("## ivw_demo_microphone Ϊʹ˷лѵdemo,run_ivwΪʹƵļѵdemoѡһַʽл##\n");
	printf("## ⣬ʹrun_ivwҪݻѴ¼ƲΪIVW_AUDIO_FILE_NAMEָƣbin/audioļ##\n");
	printf("###############################################################################################################\n\n");
	
	printf("Ƶ? \n0: ļ\n1:MIC˵\n");
	scanf("%d", &aud_src);
	if (aud_src) 
	{
		ivw_demo_microphone(NULL, ssb_param);
	}
	else
	{
		run_ivw(NULL, IVW_AUDIO_FILE_NAME, ssb_param);  
	}

	sleep_ms(2000);
exit:
	printf("˳ ...\n");
	_getch();
	MSPLogout(); //˳¼
	return 0;
}
